package com.nbcio.cd.controller;

import cn.dev33.satoken.annotation.SaCheckPermission;
import com.nbcio.cd.domain.vo.CdFileVo;
import com.nbcio.cd.service.ICdFileService;
import com.nbcio.common.core.domain.R;
import com.nbcio.common.web.core.BaseController;
import com.nbcio.common.log.annotation.Log;
import com.nbcio.common.log.enums.BusinessType;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import java.io.IOException;
import java.util.List;

/**
 * 云网盘文件Controller
 *
 * @author nbacheng
 */
@Slf4j
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/cd/file")
public class CdFileController {

    private final ICdFileService cdFileService;

    /**
     * 上传文件
     */
    @SaCheckPermission("cd:file:upload")
    @Log(title = "云网盘文件", businessType = BusinessType.INSERT)
    @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public R<CdFileVo> uploadFile(@RequestParam("file") MultipartFile file,
                                @RequestParam("folderId") @NotEmpty(message = "文件夹ID不能为空") String folderIdStr) {
        try {
            Long folderId = Long.parseLong(folderIdStr);
            CdFileVo fileVo = cdFileService.uploadFile(file, folderId);
            return R.ok(fileVo);
        } catch (NumberFormatException e) {
            log.error("文件夹ID格式错误: {}", folderIdStr);
            return R.fail("文件夹ID格式错误");
        } catch (Exception e) {
            log.error("上传文件失败: {}", e.getMessage(), e);
            return R.fail("上传文件失败: " + e.getMessage());
        }
    }

    /**
     * 下载文件
     */
    @GetMapping("/download/{fileId}")
    public void downloadFile(@PathVariable @NotNull(message = "文件ID不能为空") Long fileId,
                            HttpServletResponse response) {
        try {
            cdFileService.downloadFile(fileId, response);
        } catch (Exception e) {
            log.error("下载文件失败: {}", e.getMessage(), e);
            throw new RuntimeException("下载文件失败: " + e.getMessage());
        }
    }

    /**
     * 预览文件 - 返回URL（实际使用下载接口）
     */
    @SaCheckPermission("cd:file:preview")
    @GetMapping("/preview/{fileId}")
    public R<String> previewFile(@PathVariable @NotNull(message = "文件ID不能为空") Long fileId) {
        try {
            String previewUrl = cdFileService.previewFile(fileId);
            return R.ok(previewUrl);
        } catch (Exception e) {
            log.error("预览文件失败: {}", e.getMessage(), e);
            return R.fail("预览文件失败: " + e.getMessage());
        }
    }

    /**
     * 预览Office文档 - 返回HTML内容
     * 注意：已配置在 security.excludes 中，不需要 token 认证
     */
    @GetMapping("/preview-html/{fileId}")
    public void previewHtml(@PathVariable @NotNull(message = "文件ID不能为空") Long fileId,
                           HttpServletResponse response) {
        try {
            cdFileService.previewHtml(fileId, response);
        } catch (Exception e) {
            log.error("预览HTML失败: {}", e.getMessage(), e);
            try {
                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                response.getWriter().write("预览失败: " + e.getMessage());
            } catch (IOException ignored) {
            }
        }
    }

    /**
     * 重命名文件
     */
    @SaCheckPermission("cd:file:edit")
    @Log(title = "云网盘文件", businessType = BusinessType.UPDATE)
    @PutMapping("/rename")
    public R<Boolean> renameFile(@RequestParam @NotNull(message = "文件ID不能为空") Long fileId,
                               @RequestParam @NotEmpty(message = "新文件名不能为空") String newName) {
        try {
            Boolean result = cdFileService.renameFile(fileId, newName);
            return R.ok(result);
        } catch (Exception e) {
            log.error("重命名文件失败: {}", e.getMessage(), e);
            return R.fail("重命名文件失败: " + e.getMessage());
        }
    }

    /**
     * 移动文件
     */
    @SaCheckPermission("cd:file:edit")
    @Log(title = "云网盘文件", businessType = BusinessType.UPDATE)
    @PostMapping("/move")
    public R<Boolean> moveFile(@RequestParam @NotNull(message = "文件ID不能为空") Long fileId,
                              @RequestParam @NotNull(message = "目标文件夹ID不能为空") Long targetFolderId) {
        try {
            Boolean result = cdFileService.moveFile(fileId, targetFolderId);
            return R.ok(result);
        } catch (Exception e) {
            log.error("移动文件失败: {}", e.getMessage(), e);
            return R.fail("移动文件失败: " + e.getMessage());
        }
    }

    /**
     * 复制文件
     */
    @SaCheckPermission("cd:file:edit")
    @Log(title = "云网盘文件", businessType = BusinessType.INSERT)
    @PostMapping("/copy")
    public R<Boolean> copyFile(@RequestParam @NotNull(message = "文件ID不能为空") Long fileId,
                              @RequestParam @NotNull(message = "目标文件夹ID不能为空") Long targetFolderId) {
        try {
            Boolean result = cdFileService.copyFile(fileId, targetFolderId);
            return R.ok(result);
        } catch (Exception e) {
            log.error("复制文件失败: {}", e.getMessage(), e);
            return R.fail("复制文件失败: " + e.getMessage());
        }
    }

    /**
     * 删除文件
     */
    @SaCheckPermission("cd:file:remove")
    @Log(title = "云网盘文件", businessType = BusinessType.DELETE)
    @DeleteMapping("/{fileIds}")
    public R<Boolean> deleteFiles(@PathVariable @NotEmpty(message = "文件ID不能为空") Long[] fileIds) {
        try {
            Boolean result = cdFileService.deleteFiles(List.of(fileIds));
            return R.ok(result);
        } catch (Exception e) {
            log.error("删除文件失败: {}", e.getMessage(), e);
            return R.fail("删除文件失败: " + e.getMessage());
        }
    }

    /**
     * 查询文件列表
     */
    @SaCheckPermission("cd:file:list")
    @GetMapping("/list")
    public R<List<CdFileVo>> queryFileList(@RequestParam @NotNull(message = "文件夹ID不能为空") Long folderId,
                                                @RequestParam(required = false) String fileName,
                                                @RequestParam(required = false) String fileType,
                                                CdFileVo pageQuery) {
        try {
            return cdFileService.queryFileList(folderId, fileName, fileType, pageQuery);
        } catch (Exception e) {
            log.error("查询文件列表失败: {}", e.getMessage(), e);
            throw new RuntimeException("查询文件列表失败: " + e.getMessage());
        }
    }

    /**
     * 搜索文件
     */
    @SaCheckPermission("cd:file:list")
    @GetMapping("/search")
    public R<List<CdFileVo>> searchFiles(@RequestParam(required = false) String keyword,
                                             @RequestParam(required = false) String fileType,
                                             CdFileVo pageQuery) {
        try {
            return cdFileService.searchFiles(keyword, fileType, pageQuery);
        } catch (Exception e) {
            log.error("搜索文件失败: {}", e.getMessage(), e);
            throw new RuntimeException("搜索文件失败: " + e.getMessage());
        }
    }

    /**
     * 获取文件详情
     */
    @SaCheckPermission("cd:file:query")
    @GetMapping("/{fileId}")
    public R<CdFileVo> getFileInfo(@PathVariable @NotNull(message = "文件ID不能为空") Long fileId) {
        try {
            CdFileVo fileVo = cdFileService.getFileInfo(fileId);
            return R.ok(fileVo);
        } catch (Exception e) {
            log.error("获取文件详情失败: {}", e.getMessage(), e);
            return R.fail("获取文件详情失败: " + e.getMessage());
        }
    }

    /**
     * 检查文件权限
     */
    @SaCheckPermission("cd:file:query")
    @GetMapping("/permission/{fileId}")
    public R<Boolean> checkFilePermission(@PathVariable @NotNull(message = "文件ID不能为空") Long fileId,
                                        @RequestParam @NotEmpty(message = "权限类型不能为空") String permissionType) {
        try {
            Boolean hasPermission = cdFileService.checkFilePermission(fileId, permissionType);
            return R.ok(hasPermission);
        } catch (Exception e) {
            log.error("检查文件权限失败: {}", e.getMessage(), e);
            return R.fail("检查文件权限失败: " + e.getMessage());
        }
    }
}
